﻿using MyLibrary.Function;
using Prism.Commands;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using Serial_Communication.Common;
using Serial_Communication.Common.Models;
using Serial_Communication.Extensions;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Threading;
using static Serial_Communication.Common.Models.SerialPortPageModel;
using Parity = Serial_Communication.Common.Models.Parity;
using StopBits = Serial_Communication.Common.Models.StopBits;

namespace Serial_Communication.ViewModels
{
    public class SerialPortPageViewModel : BindableBase
    {
        private SerialPort ComDevice = new SerialPort();

        public DelegateCommand<string> ExecuteCommand { get; private set; }

        public SerialPortPageViewModel()
        {
            SerialPortPageModel = new SerialPortPageModel();

            ExecuteCommand = new DelegateCommand<string>(Execute);

            ComDevice.DataReceived += new SerialDataReceivedEventHandler(ReceivedText);

            DataInitialization();

        }

       

        private SerialPortPageModel serialPortPageModel;

        public SerialPortPageModel SerialPortPageModel
        {
            get { return serialPortPageModel; }
            set { serialPortPageModel = value; RaisePropertyChanged(); }
        }

        //委托命令执行事件
        private async void Execute(string obj)
        {
            switch (obj)
            {
                case "OpenPort": OpenPort(); break;
                case "SendData": await SendText(); break;
                case "CleanDisplay": CleanDisplay(); break;
                case "Circulate": CirculateSend(); break;
                case "CleanNum":CleanNum(); break;
            }
        }

        

        public void OpenPort()
        {
            if (!SerialPort.GetPortNames().Any() || string.IsNullOrWhiteSpace(SerialPortPageModel.SelectedSerialPortName))
            {
                MessageBox.Show("该设备没有发现端口(COM和LPT)", "警告");
                GetPortName();
                return;
            }
            switch (ComDevice.IsOpen)
            {
                case true:
                    try
                    {
                        ComDevice.Close();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "错误", MessageBoxButton.YesNo, MessageBoxImage.Information);
                        return;
                    }
                    SerialPortPageModel.PortOpenButton = new string[4] { "打开串口", "#676767", "TRUE", "FALSE" };
                    break;
                case false:
                    ComDevice.PortName = SerialPortPageModel.SelectedSerialPortName;
                    ComDevice.BaudRate = SerialPortPageModel.SelectedBaudRate;
                    ComDevice.DataBits = SerialPortPageModel.SelectedDataBits;
                    ComDevice.StopBits = SerialPortPageModel.SelectedStopBits;
                    ComDevice.Parity = SerialPortPageModel.SelectedParity;
                    try
                    {
                        ComDevice.Open();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, "错误", MessageBoxButton.YesNo, MessageBoxImage.Information);
                        return;
                    }
                    SerialPortPageModel.PortOpenButton = new string[4] { "关闭串口", "#7d4dcd", "FALSE", "TRUE" };
                    break;
            }
        }

        string txtSend = "";

        private async Task SendText()
        {
            try
            {
                if (string.IsNullOrWhiteSpace(SerialPortPageModel.SendText)) return;
                txtSend = SerialPortPageModel.SendText.Trim().Replace(" ", "").ToUpper();
                if (SerialPortPageModel.SendSet.SendIsHex)
                {
                    byte[] arraySend = DataConvert.ToHexByteArray(txtSend);
                    ComDevice.Write(arraySend, 0, arraySend.Length);
                    SerialPortPageModel.SendNum += 1;
                    SerialPortPageModel.SendByteNum += arraySend.Length;
                }
                else if (SerialPortPageModel.SendSet.SendIsAscii)
                {
                    ComDevice.Write(txtSend);
                    SerialPortPageModel.SendNum += 1; 
                    SerialPortPageModel.SendByteNum += Encoding.ASCII.GetBytes(txtSend).Length; 
                }

                StringBuilder txtSendText = new StringBuilder(50);

                if (SerialPortPageModel.ReceiveSet.DisplaySend)
                {
                    if (SerialPortPageModel.ReceiveSet.DisplayTime)
                    {
                        txtSendText.Append(DateTime.Now.ToString(">> [ HH : mm : ss : ffff ] "));
                    }
                    if (SerialPortPageModel.ReceiveSet.AutoLineFeed)
                    {
                        if (SerialPortPageModel.SendSet.SendIsHex)
                        {

                            txtSendText.Append(DataConvert.ToHexByteString(txtSend));
                            txtSendText.Append("\r\n");
                        }
                        else
                        {
                            txtSendText.Append(txtSend);
                            txtSendText.Append("\r\n");
                        }
                    }
                    else
                    {
                        if (SerialPortPageModel.SendSet.SendIsHex)
                        {
                            txtSendText.Append(DataConvert.ToHexByteString(txtSend));
                        }
                        else
                        {
                            txtSendText.Append(txtSend);
                        }
                    }
                    // 限制文本长度为25000个字符
                    const int MaxLength = 25000;
                    // 如果为 null，初始化为一个空字符串
                    if (SerialPortPageModel.ReceiveText == null)
                    {
                        SerialPortPageModel.ReceiveText = string.Empty;
                    }

                    // 添加新的文本
                    SerialPortPageModel.ReceiveText += txtSendText;

                    // 如果当前文本长度超过最大长度，删除第一行
                    if (SerialPortPageModel.ReceiveText.Length > MaxLength)
                    {
                        if (SerialPortPageModel.ReceiveSet.AutoLineFeed)
                        {
                            int index = SerialPortPageModel.ReceiveText.IndexOf('\n');
                            if (index >= 0)
                            {
                                SerialPortPageModel.ReceiveText = SerialPortPageModel.ReceiveText.Substring(index + 1);
                            }
                            else
                            {
                                SerialPortPageModel.ReceiveText = string.Empty;
                            }
                        }
                        else
                        {
                            // 删除ReceiveText开头的超过MaxLength的部分
                            SerialPortPageModel.ReceiveText = SerialPortPageModel.ReceiveText.Substring(SerialPortPageModel.ReceiveText.Length - MaxLength);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private async void ReceivedText(object sender, SerialDataReceivedEventArgs e)
        {
            await StartDataFetchLoop();
        }


        private async Task StartDataFetchLoop()
        {
            int byteNum = 0;
            do
            {
                byteNum  = ComDevice.BytesToRead;
                Thread.Sleep(20);
            }
            while (ComDevice.BytesToRead != byteNum && byteNum < 1024);

            if (byteNum == 0) return;

            byte[] receivedBuffer = new byte[byteNum];
            ComDevice.Read(receivedBuffer, 0, byteNum);
            SerialPortPageModel.ReceivedByteNum += byteNum;
            SerialPortPageModel.ReceivedNum += 1;
            // 在后台线程获取数据
            await Task.Run(() =>
            {
                StringBuilder txtReceivedText = new StringBuilder(); // 使用默认容量

                if (SerialPortPageModel.ReceiveSet.DisplayTime)
                {
                    txtReceivedText.Append(DateTime.Now.ToString("<< [ HH : mm : ss : ffff ] "));
                    //TimeStamp = DateTime.UtcNow.ToString("yyyy-MM-dd ");
                }

                if (SerialPortPageModel.ReceiveSet.ReceiveIsHex)
                {
                    txtReceivedText.Append(GetHexString(receivedBuffer, 0, byteNum));
                }
                else if (SerialPortPageModel.ReceiveSet.ReceiveIsAscii) // 修正条件
                {
                    txtReceivedText.Append(Encoding.UTF8.GetString(receivedBuffer, 0, byteNum));
                }

                if (SerialPortPageModel.ReceiveSet.AutoLineFeed)
                {
                    txtReceivedText.Append("\r\n");
                }

                App.Current.Dispatcher.Invoke(() =>
                {
                // 限制文本长度为25000个字符
                const int MaxLength = 25000;
                // 如果为 null，初始化为一个空字符串
                if (SerialPortPageModel.ReceiveText == null)
                {
                    SerialPortPageModel.ReceiveText = string.Empty;
                }

                // 添加新的文本
                SerialPortPageModel.ReceiveText += txtReceivedText;

                    // 如果当前文本长度超过最大长度，删除第一行
                    if (SerialPortPageModel.ReceiveText.Length > MaxLength)
                    {
                        if (SerialPortPageModel.ReceiveSet.AutoLineFeed)
                        {
                            int index = SerialPortPageModel.ReceiveText.IndexOf('\n');
                            if (index >= 0)
                            {
                                SerialPortPageModel.ReceiveText = SerialPortPageModel.ReceiveText.Substring(index + 1);
                            }
                            else
                            {
                                SerialPortPageModel.ReceiveText = string.Empty;
                            }
                        }
                        else
                        {
                            // 删除ReceiveText开头的超过MaxLength的部分
                            SerialPortPageModel.ReceiveText = SerialPortPageModel.ReceiveText.Substring(SerialPortPageModel.ReceiveText.Length - MaxLength);
                        }
                    }
                });
            });

            //延迟一段时间
            await Task.Delay(TimeSpan.FromMilliseconds(10)); // 50毫秒延迟
        }



        private static StringBuilder GetHexString(byte[] data, int offset, int length)
        {
            StringBuilder sb = new StringBuilder(length * 3);
            for (int i = offset; i < (offset + length); i++)
            {
                sb.Append(data[i].ToString("X2") + " ");
            }
            return sb;
        }

        private void CirculateSend()
        {

            if (SerialPortPageModel.SendSet.Circulate && ComDevice.IsOpen)
            {

                Task.Factory.StartNew(async () =>
                {
                    while (SerialPortPageModel.SendSet.Circulate)
                    {
                        await SendText();
                        Thread.Sleep(SerialPortPageModel.SendSet.CirculateTime);
                    }
                });
            }

        }

        async void DataInitialization()
        { 
            SerialPortPageModel.PortOpenButton = new string[4] { "打开串口", "#676767", "TRUE", "FALSE" };

            SerialPortPageModel.ReceiveSet = new ReceiveSet { ReceiveIsAscii = false, ReceiveIsHex = true, AutoLineFeed = true, DisplaySend = true, DisplayTime = true };

            SerialPortPageModel.SendSet = new SendSet { SendIsAscii = false, SendIsHex = true, Circulate = false, CirculateTime = 2000 };

            SerialPortPageModel.BaudRate = new List<BaudRate>
            {
                new BaudRate{Description="300",SelectedModel=300},
                new BaudRate{Description="600",SelectedModel=600},
                new BaudRate{Description="1200",SelectedModel=1200},
                new BaudRate{Description="2400",SelectedModel=2400},
                new BaudRate{Description="4800",SelectedModel=4800},
                new BaudRate{Description="9600",SelectedModel=9600},
                new BaudRate{Description="14400",SelectedModel=14400},
                new BaudRate{Description="19200",SelectedModel=19200},
                new BaudRate{Description="38400",SelectedModel=38400},
                new BaudRate{Description="56000",SelectedModel=56000},
                new BaudRate{Description="57600",SelectedModel=57600},
                new BaudRate{Description="115200",SelectedModel=115200},
                new BaudRate{Description="128000",SelectedModel=128000},
                new BaudRate{Description="256000",SelectedModel=256000},
                new BaudRate{Description="460800",SelectedModel=460800},
                new BaudRate{Description="512000",SelectedModel=512000},
                new BaudRate{Description="750000",SelectedModel=750000},
                new BaudRate{Description="921600",SelectedModel=921600},
                new BaudRate{Description="1500000",SelectedModel=1500000},
            };
            SerialPortPageModel.SelectedBaudRate = SerialPortPageModel.BaudRate[5].SelectedModel;

            SerialPortPageModel.DataBits = new List<DataBits>
            {
                new DataBits{Description="5",SelectedModel=5},
                new DataBits{Description="6",SelectedModel=6},
                new DataBits{Description="7",SelectedModel=7},
                new DataBits{Description="8",SelectedModel=8},
            };
            SerialPortPageModel.SelectedDataBits = SerialPortPageModel.DataBits[3].SelectedModel;

            SerialPortPageModel.StopBits = new List<StopBits>
            {
                new StopBits { Description = "One", SelectedModel = System.IO.Ports.StopBits.One },
                new StopBits { Description = "OnePointFive", SelectedModel = System.IO.Ports.StopBits.OnePointFive },
                new StopBits { Description = "Two", SelectedModel = System.IO.Ports.StopBits.Two },

            };
            SerialPortPageModel.SelectedStopBits = SerialPortPageModel.StopBits[0].SelectedModel;

            SerialPortPageModel.Parity = new List<Parity>
            {
                new Parity { Description = "None", SelectedModel = System.IO.Ports.Parity.None },
                new Parity { Description = "Odd", SelectedModel = System.IO.Ports.Parity.Odd },
                new Parity { Description = "Even", SelectedModel = System.IO.Ports.Parity.Even },
                new Parity { Description = "Mark", SelectedModel = System.IO.Ports.Parity.Mark },

            };
            SerialPortPageModel.SelectedParity = SerialPortPageModel.Parity[0].SelectedModel;
            //SerialPortPageModel.SerialPortName = new List<string>();
            SerialPortPageModel.SerialPortName = new string[0];
            await GetPortName();
        }

        string[] SerialPortName;

        private async Task GetPortName()
        {
            while (true)
            {
                //在后台线程获取数据
                await Task.Run(async () =>
                {
                    SerialPortName = SerialPort.GetPortNames();
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        if (!ArraysEqual(SerialPortName, SerialPortPageModel.SerialPortName))
                        {
                            SerialPortPageModel.SerialPortName = SerialPortName;
                            if (SerialPortPageModel.SerialPortName.Length > 0) 
                            {
                                SerialPortPageModel.SelectedSerialPortName = SerialPortPageModel.SerialPortName[0];
                            } 
                        }
                    });
                });

                // 延迟一段时间
                await Task.Delay(TimeSpan.FromMilliseconds(50)); // 50毫秒延迟
            }
        }

        private bool ArraysEqual(string[] array1, string[] array2)
        {
            // 检查两个字符串数组是否相等
            if (array1 == null || array2 == null)
                return array1 == array2;

            if (array1.Length != array2.Length)
                return false;

            for (int i = 0; i < array1.Length; i++)
            {
                if (array1[i] != array2[i])
                    return false;
            }

            return true;
        }

        public void CleanDisplay()
        {
            SerialPortPageModel.ReceiveText = "";
            CleanNum();
        }

        private void CleanNum()
        {
            SerialPortPageModel.SendNum = 0;
            SerialPortPageModel.SendByteNum = 0;
            SerialPortPageModel.ReceivedByteNum = 0;
            SerialPortPageModel.ReceivedNum = 0;
        }
    }
}

